package com.cjz.tool.qr.ui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class CaptureScreenPanel extends JPanel implements MouseListener, MouseMotionListener {

	private static final long serialVersionUID = 3455259993352413600L;

	private JFrame captureScreenFrame;
	private BufferedImage bufferedImage;
	private int width, height;
	private int startX, startY, endX, endY, tempX, tempY;
	private States current = States.DEFAULT;
	private Rectangle[] dragDotRect;
	private Rectangle selectedArea = new Rectangle(0, 0, 0, 0);

	public interface OnGetQrLinstener {
		void onGet(BufferedImage bi);

		void onCancel();
	}

	OnGetQrLinstener getQRListener;

	public void setGetQRListener(OnGetQrLinstener getQRListener) {
		this.getQRListener = getQRListener;
	}

	enum States {
		NORTH_WEST(new Cursor(Cursor.NW_RESIZE_CURSOR)), //
		NORTH(new Cursor(Cursor.N_RESIZE_CURSOR)), //
		NORTH_EAST(new Cursor(Cursor.NE_RESIZE_CURSOR)), //
		EAST(new Cursor(Cursor.E_RESIZE_CURSOR)), //
		SOUTH_EAST(new Cursor(Cursor.SE_RESIZE_CURSOR)), //
		SOUTH(new Cursor(Cursor.S_RESIZE_CURSOR)), //
		SOUTH_WEST(new Cursor(Cursor.SW_RESIZE_CURSOR)), //
		WEST(new Cursor(Cursor.W_RESIZE_CURSOR)), //
		MOVE(new Cursor(Cursor.MOVE_CURSOR)), //
		DEFAULT(new Cursor(Cursor.DEFAULT_CURSOR));
		private Cursor cs;

		States(Cursor cs) {
			this.cs = cs;
		}

		public Cursor getCursor() {
			return cs;
		}
	}

	public CaptureScreenPanel(JFrame jf, BufferedImage bi) {
		this.captureScreenFrame = jf;
		this.bufferedImage = bi;
		this.width = bi.getWidth();
		this.height = bi.getHeight();
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		initRecs();
	}

	private void initRecs() {
		dragDotRect = new Rectangle[8];
		for (int i = 0; i < dragDotRect.length; i++) {
			dragDotRect[i] = new Rectangle();
		}
	}

	@Override
	public void paintComponent(Graphics g) {

		g.drawImage(bufferedImage, 0, 0, width, height, this);

		int maskStartX = Math.min(startX, endX);
		int maskEndX = Math.max(startX, endX);
		int maskStartY = Math.min(startY, endY);
		int maskEndY = Math.max(startY, endY);
		g.setColor(new Color(99, 99, 99, 80));
		g.fillRect(0, 0, getWidth(), maskStartY);
		g.fillRect(0, maskStartY, maskStartX, maskEndY - maskStartY);
		g.fillRect(maskEndX, maskStartY, getWidth() - maskEndX, maskEndY - maskStartY);
		g.fillRect(0, maskEndY, getWidth(), getHeight() - maskEndY);

		g.setColor(Color.RED);
		g.drawLine(startX, startY, endX, startY);
		g.drawLine(startX, endY, endX, endY);
		g.drawLine(startX, startY, startX, endY);
		g.drawLine(endX, startY, endX, endY);

		int x = startX < endX ? startX : endX;
		int y = startY < endY ? startY : endY;
		selectedArea = new Rectangle(x, y, Math.abs(endX - startX), Math.abs(endY - startY));
		int x1 = (startX + endX) / 2;
		int y1 = (startY + endY) / 2;
		g.fillRect(x1 - 2, startY - 2, 5, 5);
		g.fillRect(x1 - 2, endY - 2, 5, 5);
		g.fillRect(startX - 2, y1 - 2, 5, 5);
		g.fillRect(endX - 2, y1 - 2, 5, 5);
		g.fillRect(startX - 2, startY - 2, 5, 5);
		g.fillRect(startX - 2, endY - 2, 5, 5);
		g.fillRect(endX - 2, startY - 2, 5, 5);
		g.fillRect(endX - 2, endY - 2, 5, 5);
		dragDotRect[0] = new Rectangle(x - 5, y - 5, 10, 10);
		dragDotRect[1] = new Rectangle(x1 - 5, y - 5, 10, 10);
		dragDotRect[2] = new Rectangle((startX > endX ? startX : endX) - 5, y - 5, 10, 10);
		dragDotRect[3] = new Rectangle((startX > endX ? startX : endX) - 5, y1 - 5, 10, 10);
		dragDotRect[4] = new Rectangle((startX > endX ? startX : endX) - 5, (startY > endY ? startY : endY) - 5, 10, 10);
		dragDotRect[5] = new Rectangle(x1 - 5, (startY > endY ? startY : endY) - 5, 10, 10);
		dragDotRect[6] = new Rectangle(x - 5, (startY > endY ? startY : endY) - 5, 10, 10);
		dragDotRect[7] = new Rectangle(x - 5, y1 - 5, 10, 10);
	}

	public void mouseMoved(MouseEvent me) {
		if (selectedArea.contains(me.getPoint())) {
			this.setCursor(new Cursor(Cursor.MOVE_CURSOR));
			current = States.MOVE;
		} else {
			States[] st = States.values();
			for (int i = 0; i < dragDotRect.length; i++) {
				if (dragDotRect[i].contains(me.getPoint())) {
					current = st[i];
					this.setCursor(st[i].getCursor());
					return;
				}
			}
			this.setCursor(null);
			current = States.DEFAULT;
		}
	}

	public void mouseExited(MouseEvent me) {

	}

	public void mouseEntered(MouseEvent me) {
	}

	public void mouseDragged(MouseEvent me) {
		int x = me.getX();
		int y = me.getY();

		if (current == States.MOVE) {
			startX += (x - tempX);
			startY += (y - tempY);
			endX += (x - tempX);
			endY += (y - tempY);
			tempX = x;
			tempY = y;
		} else if (current == States.EAST) {
			if (startX > endX) {
				startX += (x - tempX);
				tempX = x;
			} else {
				endX += (x - tempX);
				tempX = x;
			}
		} else if (current == States.NORTH) {
			if (startY < endY) {
				startY += (y - tempY);
				tempY = y;
			} else {
				endY += (y - tempY);
				tempY = y;
			}
		} else if (current == States.WEST) {
			if (startX < endX) {
				startX += (x - tempX);
				tempX = x;
			} else {
				endX += (x - tempX);
				tempX = x;
			}
		} else if (current == States.SOUTH) {
			if (startY > endY) {
				startY += (y - tempY);
				tempY = y;
			} else {
				endY += (y - tempY);
				tempY = y;
			}
		} else if (current == States.NORTH_EAST) {
			if (startX > endX) {
				startX += (x - tempX);
				tempX = x;
			} else {
				endX += (x - tempX);
				tempX = x;
			}
			if (startY < endY) {
				startY += (y - tempY);
				tempY = y;
			} else {
				endY += (y - tempY);
				tempY = y;
			}
		} else if (current == States.NORTH_WEST) {
			if (startX < endX) {
				startX += (x - tempX);
				tempX = x;
			} else {
				endX += (x - tempX);
				tempX = x;
			}
			if (startY < endY) {
				startY += (y - tempY);
				tempY = y;
			} else {
				endY += (y - tempY);
				tempY = y;
			}
		} else if (current == States.SOUTH_EAST) {
			if (startY > endY) {
				startY += (y - tempY);
				tempY = y;
			} else {
				endY += (y - tempY);
				tempY = y;
			}
			if (startX > endX) {
				startX += (x - tempX);
				tempX = x;
			} else {
				endX += (x - tempX);
				tempX = x;
			}
		} else if (current == States.SOUTH_WEST) {
			if (startY > endY) {
				startY += (y - tempY);
				tempY = y;
			} else {
				endY += (y - tempY);
				tempY = y;
			}
			if (startX < endX) {
				startX += (x - tempX);
				tempX = x;
			} else {
				endX += (x - tempX);
				tempX = x;
			}
		} else {
			startX = tempX;
			startY = tempY;
			endX = me.getX();
			endY = me.getY();
		}
		this.repaint();
	}

	public void mousePressed(MouseEvent me) {
		tempX = me.getX();
		tempY = me.getY();
	}

	public void mouseReleased(MouseEvent me) {
		if (me.isPopupTrigger()) {
			if (current == States.MOVE) {
				startX = 0;
				startY = 0;
				endX = 0;
				endY = 0;
				current = States.DEFAULT;
				repaint();
			} else {
				captureScreenFrame.dispose();
				if (getQRListener != null) {
					getQRListener.onCancel();
				}

			}
		}
	}

	public void mouseClicked(MouseEvent me) {
		BufferedImage gotImage;
		if (me.getClickCount() == 2) {
			Point p = me.getPoint();
			if (selectedArea.contains(p)) {
				if (selectedArea.x + selectedArea.width < this.getWidth() && selectedArea.y + selectedArea.height < this.getHeight()) {

					gotImage = bufferedImage.getSubimage(//
							selectedArea.x < 0 ? 0 : selectedArea.x, //
							selectedArea.y < 0 ? 0 : selectedArea.y, //
							selectedArea.x < 0 ? selectedArea.width + selectedArea.x : selectedArea.width, //
							selectedArea.y < 0 ? selectedArea.height + selectedArea.y : selectedArea.height //
					);

				} else {
					int wid = selectedArea.width;
					int het = selectedArea.height;
					if (selectedArea.x + selectedArea.width >= this.getWidth()) {
						wid = this.getWidth() - selectedArea.x;
					}
					if (selectedArea.y + selectedArea.height >= this.getHeight()) {
						het = this.getHeight() - selectedArea.y;
					}
					gotImage = bufferedImage.getSubimage(//
							selectedArea.x < 0 ? 0 : selectedArea.x, //
							selectedArea.y < 0 ? 0 : selectedArea.y, //
							selectedArea.x < 0 ? wid + selectedArea.x : wid, //
							selectedArea.y < 0 ? het + selectedArea.y : het //
					);
				}

				if (getQRListener != null && gotImage != null) {
					getQRListener.onGet(gotImage);
				}

				captureScreenFrame.dispose();
			}
		}
	}

}